import json
import logging
import os
import socket
import sys
from datetime import datetime, timedelta
from django.core.exceptions import ObjectDoesNotExist
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.db import transaction
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.authentication import TokenAuthentication
from rest_framework.parsers import JSONParser
from rest_framework.views import APIView

from api_test.common.api_response import JsonResponse
from api_test.common.common import record_dynamic
from api_test.common.decorator import catch_exception
from api_test.common.util import Util
from api_test.common_exception.exceptions import ParamsMissedException, ObjectNotFoundException
from api_test.models import Project, LocustCaseList, LocustRecord
from api_test.serializers import LocustCaseListDeserializer, LocustCaseListSerializer, LocustRecordSerializer, \
    LocustRecordDeserializer

logger = logging.getLogger(__name__)  # 这里使用 __name__ 动态搜索定义的 logger 配置，这里有一个层次关系的知识点。


class LocustTest(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @staticmethod
    def parameter_check(request):
        """
        校验参数
        """
        for param in ['host', 'path', 'method', 'thread', 'setUp', 'runTime', 'maxWait', 'minWait', 'project_id']:
            data = request.get(param)
            if not data:
                raise ParamsMissedException(param)

    @staticmethod
    def update_record_data(save_data, record_id):
        obj = LocustRecord.objects.get(id=record_id)
        if not obj:
            return ObjectNotFoundException(f'执行记录：{record_id}')
        with transaction.atomic():  # 执行错误后，帮助事务回滚
            serialize = LocustRecordDeserializer(data=save_data)
            if serialize.is_valid():
                serialize.update(obj, save_data)
                return JsonResponse(code="999999", msg="执行成功", data={"id": record_id})
            return JsonResponse(code="999995", msg="执行失败")

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['project_id', 'host', 'path', 'type', 'min_wait', 'max_wait', 'set_up', 'run_time', 'thread',
                  'protocol'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='项目id'),
            'host': openapi.Schema(type=openapi.TYPE_STRING, description="host名称"),
            'path': openapi.Schema(type=openapi.TYPE_STRING, description="接口路径"),
            'type': openapi.Schema(type=openapi.TYPE_STRING, description="接口类型(post,get,put,delete)"),
            'request': openapi.Schema(type=openapi.TYPE_OBJECT, description="接口请求参数"),
            'header': openapi.Schema(type=openapi.TYPE_OBJECT, description="接口请求头信息"),
            'min_wait': openapi.Schema(type=openapi.TYPE_STRING, description="接口调用间隔最小时间(毫秒)"),
            'max_wait': openapi.Schema(type=openapi.TYPE_STRING, description="接口调用间隔最大时间(毫秒)"),
            'thread': openapi.Schema(type=openapi.TYPE_STRING, description="线程数(个)"),
            'set_up': openapi.Schema(type=openapi.TYPE_STRING, description="单位时间启动线程数量(秒/个)"),
            'run_time': openapi.Schema(type=openapi.TYPE_STRING, description="性能执行时间(秒)"),
            'protocol': openapi.Schema(type=openapi.TYPE_STRING, description="接口协议(http,https,ws,wss)", default='http'),
            'case_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="性能测试用例id", default='0'),
        },
    ))
    @catch_exception
    def post(self, request):
        """
        执行性能测试
        """
        # 获取请求参数 请求地址：host, 接口路径：path, 接口类型：method, 接口请求参数：raw_data, 请求头信息：header
        data = JSONParser().parse(request)
        case_id = data.get('case_id', 0)
        project_id = data.get('project_id')
        if not case_id:
            self.parameter_check(data)
            host = data.get("host")
            path = data.get("path")
            method = data.get('method')
            raw_data = json.dumps(data.get('request'))
            header = json.dumps(data.get('header'))
            # 最小/最大等待时间设置默认值(若请求未传)
            min_wait = data.get('minWait', 500)
            max_wait = data.get('maxWait', 2000)
            # 获取性能测试参数:线程数thread,执行时间runTime,单位时间启动线程数setUp
            thread = data.get('thread', 10)
            set_up = data.get('setUp', 10)
            run_time = data.get('runTime', 60)
            save_data = dict(host=host, thread=thread, run_time=run_time, set_up=set_up, header=header,
                             request=raw_data, protocol=data.get('protocol'), address=path, min_wait=min_wait,
                             max_wait=max_wait, name=data.get('name'), project_id=project_id,
                             type=method, locust_case_id=0, status=2)
        else:
            if not project_id:
                raise ParamsMissedException('project_id')
            obj = LocustCaseList.objects.get(id=case_id, project_id=project_id)
            if not obj:
                return JsonResponse(code='999995', msg=f'case:{case_id}未找到')
            save_data = LocustRecordSerializer(obj).data
            host = save_data.get("host")
            path = save_data.get("address")
            method = save_data.get('type')
            raw_data = json.dumps(save_data.get('request'))
            header = json.dumps(save_data.get('header'))
            # 最小/最大等待时间设置默认值(若请求未传)
            min_wait = save_data.get('min_wait')
            max_wait = save_data.get('max_wait')
            # 获取性能测试参数:线程数thread,执行时间runTime,单位时间启动线程数setUp
            thread = save_data.get('thread')
            set_up = save_data.get('set_up')
            run_time = save_data.get('run_time')
            save_data['status'] = 2
            save_data['locust_case_id'] = case_id
        dir_path = os.path.join(os.getcwd(), 'api_test', 'locust')
        file_path = os.path.join(dir_path, 'locust_test.py')
        os.environ['LOCUSTPATH'] = path
        os.environ['LOCUSTMETHOD'] = method
        os.environ['LOCUSTREQUEST'] = raw_data
        os.environ['LOCUSTHEADER'] = header
        os.environ['MINWAIT'] = str(min_wait)
        os.environ['MAXWAIT'] = str(max_wait)
        start_time = datetime.now()
        if sys.platform == 'win32':
            report_path = f'F:\\nginx-1.18.0\\reports\\locust\\caseId_{case_id}'
        elif sys.platform == 'linux':
            report_path = f'/data/logs/locust/caseId_{case_id}'
        if not os.path.exists(report_path):
            os.mkdir(report_path)
        report_path = os.path.join(report_path, f'{start_time.strftime("%Y%m%d%H%M%S")}.html')
        hostname = socket.gethostname()
        ip = socket.gethostbyname(hostname)
        with transaction.atomic():  # 执行错误后，帮助事务回滚
            save_data['start_time'] = start_time
            save_data['request'] = raw_data
            save_data['header'] = header
            if 'id' in save_data:
                save_data.pop('id')
            serialize = LocustRecordDeserializer(data=save_data)
            if serialize.is_valid():
                serialize.save(**save_data)
                record_id = serialize.data.get("id")
            else:
                return JsonResponse(code="999995", msg="执行记录存储失败!")
        try:
            cmd = f"locust -f {file_path} --host={host} --headless -u {thread} -r {set_up} -t {run_time}s --html={report_path}"
            os.system(cmd)
            save_data[
                'report_url'] = f'http://{ip}:8082/locust/caseId_{case_id}/{start_time.strftime("%Y%m%d%H%M%S")}.html'
            save_data['status'] = 1
            end_time = datetime.now()
            save_data['end_time'] = end_time
            if end_time >= start_time + timedelta(seconds=int(run_time)):
                return self.update_record_data(save_data, record_id)
            else:
                return JsonResponse(code="999995", msg="取消执行成功!")
        except Exception as e:
            end_time = datetime.now()
            print(e.__str__())
            save_data['status'] = 0
            save_data['end_time'] = end_time
            return self.update_record_data(save_data, record_id)


class CancelLocustTest(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['record_id'],
        properties={
            'record_id': openapi.Schema(type=openapi.TYPE_STRING, description="执行记录id"),
        },
    ))
    @catch_exception
    def post(self, request):
        """
        取消执行
        """
        data = JSONParser().parse(request)
        record_id = data.get('record_id')
        locust_run_flag = Util.get_locust_process_status()
        if not locust_run_flag:
            return JsonResponse(code="999995", msg=f"后台不存在locust进程!")
        if not record_id:
            obj = LocustRecord.objects.filter(status=2)
            if obj:
                if len(obj) != 1:
                    return JsonResponse(code="999995", msg=f"数据异常!")
                else:
                    record_id = obj[0].id
            else:
                return JsonResponse(code="999995", msg=f"不存在执行中的记录!")
        obj = LocustRecord.objects.filter(id=record_id)
        if not obj:
            return JsonResponse(code="999995", msg=f"执行记录:{record_id}不存在!")
        if obj[0].status != '2':
            return JsonResponse(code="999996", msg=f"取消执行失败,执行记录状态错误!")
        with transaction.atomic():  # 执行错误后，帮助事务回滚
            Util.kill_process_with_name()
            obj = LocustRecord.objects.get(id=record_id)
            save_data = LocustRecordSerializer(obj).data
            save_data['status'] = 0
            save_data['report_url'] = None
            save_data['request'] = json.dumps(save_data['request'])
            save_data['header'] = json.dumps(save_data['header'])
            serialize = LocustRecordDeserializer(data=save_data)
            if serialize.is_valid():
                serialize.update(obj, save_data)
                return JsonResponse(code="999999", msg="取消执行成功", data={"id": record_id})
            print(serialize.errors)
            return JsonResponse(code="999995", msg="取消执行失败")


class AddLocustCase(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @staticmethod
    def parameter_check(request):
        """
        校验参数
        """
        for param in ['host', 'path', 'method', 'thread', 'setUp', 'runTime', 'maxWait', 'minWait']:
            data = request.get(param)
            if not data:
                raise ParamsMissedException(param)

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['project_id', 'host', 'path', 'type', 'min_wait', 'max_wait', 'set_up', 'run_time', 'thread',
                  'protocol'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='项目id'),
            'host': openapi.Schema(type=openapi.TYPE_STRING, description="host名称"),
            'path': openapi.Schema(type=openapi.TYPE_STRING, description="接口路径"),
            'type': openapi.Schema(type=openapi.TYPE_STRING, description="接口类型(post,get,put,delete)"),
            'request': openapi.Schema(type=openapi.TYPE_OBJECT, description="接口请求参数"),
            'header': openapi.Schema(type=openapi.TYPE_OBJECT, description="接口请求头信息"),
            'min_wait': openapi.Schema(type=openapi.TYPE_STRING, description="接口调用间隔最小时间(毫秒)"),
            'max_wait': openapi.Schema(type=openapi.TYPE_STRING, description="接口调用间隔最大时间(毫秒)"),
            'thread': openapi.Schema(type=openapi.TYPE_STRING, description="线程数(个)"),
            'set_up': openapi.Schema(type=openapi.TYPE_STRING, description="单位时间启动线程数量(秒/个)"),
            'run_time': openapi.Schema(type=openapi.TYPE_STRING, description="性能执行时间(秒)"),
            'protocol': openapi.Schema(type=openapi.TYPE_STRING, description="接口协议(http,https,ws,wss)", default='http'),
        },
    ))
    @catch_exception
    def post(self, request):
        """
        添加性能测试用例
        """
        data = JSONParser().parse(request)
        self.parameter_check(data)
        project_id = data.get('project_id')
        data["userUpdate"] = request.user.pk
        raw_data = dict(host=data.get('host'), thread=data.get('thread', '10'), run_time=data.get('runTime', '60'),
                        set_up=data.get('setUp', '60'), header=json.dumps(data.get('header')),
                        request=json.dumps(data.get('request')),
                        protocol=data.get('protocol'), address=data.get('path'), min_wait=data.get('minWait'),
                        max_wait=data.get('maxWait'), name=data.get('name'), project_id=project_id,
                        type=data.get('method'), create_time=datetime.now())
        try:
            obj = Project.objects.get(id=data["project_id"], status=True)
            if not request.user.is_superuser and obj.user.is_superuser:
                return JsonResponse(code="999983", msg="无操作权限！")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在or已禁用!")
        count = LocustCaseList.objects.filter(name=data["name"], project_id=data["project_id"]).count()
        if count > 0:
            return JsonResponse(code="999997", msg=f"用例{data['name']}已存在!")
        else:
            with transaction.atomic():  # 执行错误后，帮助事务回滚
                serialize = LocustCaseListDeserializer(data=raw_data)
                if serialize.is_valid():
                    serialize.save(**raw_data)
                    case_id = serialize.data.get("id")
                    record_dynamic(project=project_id,
                                   _type="新增", operationObject="用例", user=request.user.pk,
                                   data="新增性能测试用例“%s”" % data["name"])
                    return JsonResponse(code="999999", msg="新增成功!", data={"case_id": case_id})
                return JsonResponse(code="999996", msg="新增失败!")


class LocustRecordListView(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @swagger_auto_schema(manual_parameters=[
        openapi.Parameter(name="name", in_=openapi.IN_QUERY, type=openapi.TYPE_STRING, description="性能测试用例名称"),
        openapi.Parameter(name="page_size", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER, description="单页显示数量"),
        openapi.Parameter(name="page", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER, description="页码"),
        openapi.Parameter(name="project_id", in_=openapi.IN_QUERY, type=openapi.TYPE_STRING, description="项目id"),
        openapi.Parameter(name="case_id", in_=openapi.IN_QUERY, type=openapi.TYPE_STRING, description="用例id"),
        openapi.Parameter(name="status", in_=openapi.IN_QUERY, type=openapi.TYPE_STRING, description="记录状态"),

    ])
    @catch_exception
    def get(self, request):
        """
        get请求
        :param request:
        :return:
        获取性能执行记录列表
        """
        page_size = request.GET.get("page_size", 10)
        page = request.GET.get("page", 1)
        name = request.GET.get('name')
        project_id = request.GET.get('project_id')
        case_id = request.GET.get('case_id', 0)
        status = int(request.GET.get('status')) if request.GET.get('status') else None
        locust_run_flag = Util.get_locust_process_status()
        if status == 2:
            obj = LocustRecord.objects.filter(status=status).order_by('id')
            if obj:
                if locust_run_flag:
                    if len(obj) == 1:
                        obj = obj.filter(project_id=project_id)
                        if obj:
                            serializer = LocustRecordSerializer(obj, many=True)
                            return JsonResponse(code='999999', msg=f'获取执行中记录成功!', data={"data": serializer.data[0]})
                        else:
                            return JsonResponse(code='999990', msg=f'其他项目下存在执行中的记录!')
                    else:
                        return JsonResponse(code='999991', msg=f'数据异常,存在多条执行中的记录')
                else:
                    with transaction.atomic():  # 执行错误后，帮助事务回滚
                        for j in obj:
                            j.status = 1 if j.report_url else 0
                            j.save()
            else:
                return JsonResponse(code='999999', msg=f'执行中的记录为空', data=[])
        if not project_id:
            raise ParamsMissedException('参数project_id缺失')
        obj = LocustRecord.objects.filter(project_id=project_id, locust_case_id=case_id).order_by('id')
        if not obj:
            return JsonResponse(code='999999', data=[], msg=f'性能测试执行记录列表为空!')
        try:
            page_size = int(page_size)
            page = int(page)
        except (TypeError, ValueError):
            return JsonResponse(code="999985", msg="page and page_size must be integer!")
        if not name:
            paginator = Paginator(obj, page_size)  # paginator对象
        else:
            obi = obj.filter(name=name)
            if not obi:
                return JsonResponse(code='999997', data=[], msg=f'未查询到name为:{name}的记录!')
            paginator = Paginator(obi, page_size)  # paginator对象
        page_sizes = paginator.num_pages  # 总页数
        total = paginator.count
        try:
            obm = paginator.page(page)
        except PageNotAnInteger:
            obm = paginator.page(1)
        except EmptyPage:
            obm = paginator.page(paginator.num_pages)
        serializer = LocustRecordSerializer(obm, many=True)
        return JsonResponse(code='999999', msg=f'获取性能测试执行记录列表成功!', data={"data": serializer.data,
                                                                         "page_sizes": page_sizes, "total": total})


class LocustCaseListView(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @swagger_auto_schema(manual_parameters=[
        openapi.Parameter(name="name", in_=openapi.IN_QUERY, type=openapi.TYPE_STRING, description="性能测试用例名称"),
        openapi.Parameter(name="page_size", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER, description="单页显示数量"),
        openapi.Parameter(name="page", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER, description="页码"),
        openapi.Parameter(name="project_id", in_=openapi.IN_QUERY, type=openapi.TYPE_STRING, description="项目id"),

    ])
    def get(self, request):
        """
        get请求
        :param request:
        :return:
        获取性能用例列表
        """
        page_size = request.GET.get("page_size")
        page = request.GET.get("page")
        name = request.GET.get('name')
        project_id = request.GET.get('project_id')
        if not project_id:
            raise ParamsMissedException('参数project_id缺失')
        obj = LocustCaseList.objects.filter(project_id=project_id).order_by('id')
        if not obj:
            return JsonResponse(code='999999', data=[], msg=f'性能测试用例列表为空!')
        if name:
            obj = obj.filter(name=name)
            if not obj:
                return JsonResponse(code='999999', data=[], msg=f'未查询到name为:{name}的用例!')
        if not page and not page_size:
            serializer = LocustCaseListSerializer(obj, many=True)
            return JsonResponse(code='999999', msg=f'查询性能测试用例列表成功!', data={"data": serializer.data})
        else:
            try:
                page_size = int(page_size)
                page = int(page)
            except (TypeError, ValueError):
                return JsonResponse(code="999985", msg="page and page_size must be integer!")
            paginator = Paginator(obj, page_size)  # paginator对象
            page_sizes = paginator.num_pages  # 总页数
            total = paginator.count
            try:
                obm = paginator.page(page)
            except PageNotAnInteger:
                obm = paginator.page(1)
            except EmptyPage:
                obm = paginator.page(paginator.num_pages)
            serializer = LocustCaseListSerializer(obm, many=True)
            return JsonResponse(code='999999', msg=f'获取性能测试用例列表成功!', data={"data": serializer.data, "page": page,
                                                                           "page_sizes": page_sizes, "total": total})


class DelLocustCaseView(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @staticmethod
    def parameter_check(data):
        """
        校验参数
        """
        try:
            # 校验project_id, id类型为int
            for param in ['project_id', 'ids']:
                if not data.get(param):
                    return JsonResponse(code="999996", msg=f"参数{param}缺失or为空!")
            if not isinstance(data["project_id"], int):
                return JsonResponse(code="999996", msg="参数project_id类型错误!")
            if not isinstance(data['ids'], list):
                return JsonResponse(code="999996", msg="参数ids类型错误!")
            for i in data.get("ids"):
                if not isinstance(i, int):
                    return JsonResponse(code="999996", msg="参数ids了列表值类型错误!")
        except KeyError:
            return JsonResponse(code="999996", msg="参数有误!")

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['project_id', 'ids'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_INTEGER),
                                  description="待删除待用例id列表"),
        },
    ))
    def post(self, request):
        """
        删除性能测试用例
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        ids = data.get('ids')
        if result:
            return result

        pro_data = Project.objects.get(id=data["project_id"], status=True)
        if not pro_data:
            return JsonResponse(code="999995", msg="项目不存在or已禁用!")
        obj = LocustCaseList.objects.filter(id__in=ids)
        if obj:
            with transaction.atomic():  # 执行错误后，帮助事务回滚
                obj.delete()
                return JsonResponse(code="999999", msg="删除成功!")
        else:
            return JsonResponse(code="999995", msg=f"未找到数组{ids}中的用例")


class UpdateLocustCaseView(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @staticmethod
    def parameter_check(request):
        """
        校验参数
        """
        for param in ['host', 'path', 'method', 'thread', 'setUp', 'runTime', 'maxWait', 'minWait', 'project_id', 'id']:
            data = request.get(param)
            if not data:
                raise ParamsMissedException(param)

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['id', 'project_id', 'host', 'path', 'type', 'min_wait', 'max_wait', 'set_up', 'run_time', 'thread',
                  'protocol'],
        properties={
            'id': openapi.Schema(name="id", type=openapi.TYPE_INTEGER, description="用例id"),
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='项目id'),
            'host': openapi.Schema(type=openapi.TYPE_STRING, description="host名称"),
            'path': openapi.Schema(type=openapi.TYPE_STRING, description="接口路径"),
            'type': openapi.Schema(type=openapi.TYPE_STRING, description="接口类型(post,get,put,delete)"),
            'request': openapi.Schema(type=openapi.TYPE_OBJECT, description="接口请求参数"),
            'header': openapi.Schema(type=openapi.TYPE_OBJECT, description="接口请求头信息"),
            'min_wait': openapi.Schema(type=openapi.TYPE_STRING, description="接口调用间隔最小时间(毫秒)"),
            'max_wait': openapi.Schema(type=openapi.TYPE_STRING, description="接口调用间隔最大时间(毫秒)"),
            'thread': openapi.Schema(type=openapi.TYPE_STRING, description="线程数(个)"),
            'set_up': openapi.Schema(type=openapi.TYPE_STRING, description="单位时间启动线程数量(秒/个)"),
            'run_time': openapi.Schema(type=openapi.TYPE_STRING, description="性能执行时间(秒)"),
            'protocol': openapi.Schema(type=openapi.TYPE_STRING, description="接口协议(http,https,ws,wss)"),
        },
    ))
    @catch_exception
    def post(self, request):
        """
        编辑性能测试用例
        """
        data = JSONParser().parse(request)
        self.parameter_check(data)
        project_id = data.get('project_id')
        data["userUpdate"] = request.user.pk
        raw_data = dict(host=data.get('host'), thread=data.get('thread', '10'), run_time=data.get('runTime', '60'),
                        set_up=data.get('setUp', '60'), header=json.dumps(data.get('header')),
                        request=json.dumps(data.get('request')),
                        protocol=data.get('protocol'), address=data.get('path'), min_wait=data.get('minWait'),
                        max_wait=data.get('maxWait'), name=data.get('name'), project_id=project_id,
                        type=data.get('method'), update_time=datetime.now(), id=data.get('id'))
        try:
            obj = Project.objects.get(id=data["project_id"], status=True)
            if not request.user.is_superuser and obj.user.is_superuser:
                return JsonResponse(code="999983", msg="无操作权限！")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在or已禁用!")
        obj = LocustCaseList.objects.get(id=data["id"], project_id=data["project_id"])
        if not obj:
            return JsonResponse(code="999997", msg=f"项目{data['project_id']}下id为{data['id']}的用例不存在!")
        else:
            with transaction.atomic():  # 执行错误后，帮助事务回滚
                serialize = LocustCaseListDeserializer(data=raw_data)
                if serialize.is_valid():
                    serialize.update(obj, raw_data)
                    record_dynamic(project=project_id,
                                   _type="编辑", operationObject="用例", user=request.user.pk,
                                   data="编辑性能测试用例“%s”" % data["name"])
                    return JsonResponse(code="999999", msg="编辑成功!", data={"case_id": data.get('id')})
                return JsonResponse(code="999996", msg="编辑失败!")


class DelLocustRecordView(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @staticmethod
    def parameter_check(data):
        """
        校验参数
        """
        try:
            # 校验project_id, id类型为int
            for param in ['project_id', 'ids']:
                if not data.get(param):
                    return JsonResponse(code="999996", msg=f"参数{param}缺失or为空!")
            if not isinstance(data["project_id"], int):
                return JsonResponse(code="999996", msg="参数project_id类型错误!")
            if not isinstance(data['ids'], list):
                return JsonResponse(code="999996", msg="参数ids类型错误!")
            for i in data.get("ids"):
                if not isinstance(i, int):
                    return JsonResponse(code="999996", msg="参数ids了列表值类型错误!")
        except KeyError:
            return JsonResponse(code="999996", msg="参数有误!")

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['project_id', 'ids'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_INTEGER),
                                  description="待删除记录id列表"),
        },
    ))
    def post(self, request):
        """
        删除性能测试执行记录
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        ids = data.get('ids')
        if result:
            return result

        pro_data = Project.objects.get(id=data["project_id"], status=True)
        if not pro_data:
            return JsonResponse(code="999995", msg="项目不存在or已禁用!")
        obj = LocustRecord.objects.filter(id__in=ids)
        if obj:
            with transaction.atomic():  # 执行错误后，帮助事务回滚
                obj.delete()
                return JsonResponse(code="999999", msg="删除成功!")
        else:
            return JsonResponse(code="999995", msg=f"未找到数组{ids}中的记录")
